package lk.icta.core.service.impl;

import lk.icta.common.AppConstants;
import lk.icta.common.ELandRuntimeException;
import lk.icta.common.ErrorCodes;
import lk.icta.common.dao.DSDivisionDAO;
import lk.icta.common.entity.Child;
import lk.icta.common.entity.DSDivision;
import lk.icta.common.service.DocumentManagementService;
import lk.icta.common.service.MailSenderService;
import lk.icta.common.service.PresidentManagementService;
import lk.icta.common.service.SmsSenderService;
import lk.icta.common.web.ShortlistConstants;
import lk.icta.core.dao.AlienationMethodDAO;
import lk.icta.core.dao.LandApplicationDAO;
import lk.icta.core.dao.LandDAO;
import lk.icta.core.entity.*;
import lk.icta.core.service.AlienationManagementService;
import lk.icta.core.service.LandApplicationManagementService;
import lk.icta.core.service.WorkflowService;
import lk.icta.user.common.Permission;
import lk.icta.user.dao.RoleDAO;
import lk.icta.user.entity.User;
import lk.icta.user.service.UserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

public class LandApplicationManagementServiceImpl implements LandApplicationManagementService {

    private static final Logger logger = LoggerFactory.getLogger(LandApplicationManagementServiceImpl.class);
    private LandApplicationDAO landApplicationDAO;
    private AlienationMethodDAO alienationMethodDAO;
    private final DocumentManagementService documentManagementService;
    private final AlienationManagementService alienationManagementService;
    private final LandDAO landDao;
    private RoleDAO roleDAO;
    private final PresidentManagementService presidentManagementService;
    private final UserManager userManager;
    private final MailSenderService mailSenderService;
    private final WorkflowService workflowService;
    private final SmsSenderService smsSenderService;


    public LandApplicationManagementServiceImpl(LandDAO landDao, LandApplicationDAO landApplicationDAO,
                                                AlienationMethodDAO alienationMethodDAO,
                                                DocumentManagementService documentManagementService,
                                                PresidentManagementService presidentManagementService,
                                                AlienationManagementService alienationManagementService,
                                                UserManager userManager,
                                                RoleDAO roleDAO,
                                                MailSenderService mailSenderService,
                                                WorkflowService workflowService, SmsSenderService smsSenderService) {
        this.landDao = landDao;
        this.landApplicationDAO = landApplicationDAO;
        this.alienationMethodDAO = alienationMethodDAO;
        this.documentManagementService = documentManagementService;
        this.presidentManagementService = presidentManagementService;
        this.userManager = userManager;
        this.roleDAO = roleDAO;
        this.mailSenderService = mailSenderService;
        this.alienationManagementService = alienationManagementService;
        this.workflowService = workflowService;
        this.smsSenderService = smsSenderService;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addLandInitialApplication(LandApplication landApplication, User user) {
        //  if (user.getUsername().equals("onlineapplicant") || (user.isAuthorized(Permission.MANAGE_INITIAL_LAND_APPLICATION))) {
        landApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);
        //todo : IF permit and applicant is a person - get the requirement - for departments zero marks
        // if (landApplication.getPreferredAlienationMethod().getId() == 1 &&

            /* Set marks for the land application */
        if (landApplication.getAlienationMethods() != null &&
                landApplication.getHolder().getHolderType() == AppConstants.PERSON_APPLICANT) {
            setMarksForLandApplications(landApplication);
        }

        if (user != null && user.getDsDivisions() != null) {
            landApplication.setDsDivision(user.getDsDivisions().iterator().next());
        }

        if (user == null) {
            user = userManager.getUserByUserName("onlineapplicant");
        }

        landApplicationDAO.addLandApplication(landApplication, user);
        logger.debug("Add land application of land application id : {}", landApplication.getId());
        //TODO:no doc upload in initial lands. remove this
        if (landApplication.getDocumentList() != null) {
            try {
                documentManagementService.uploadfiles(user, landApplication.getDocumentList(),
                        landApplication.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addLandGrantInitialApplication(LandApplication landApplication, String permitNo, User user) {
        if (user.isAuthorized(Permission.MANAGE_INITIAL_LAND_APPLICATION)) {
            landApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);

            /* Set marks for the land application */
            if (landApplication.getAlienationMethods() != null &&
                    landApplication.getHolder().getHolderType() == AppConstants.PERSON_APPLICANT) {
                setMarksForLandApplications(landApplication);
            }

            //set Alienation
            Alienation permitAlienation = alienationManagementService.getActiveApprovedAlienationByPermitNo(permitNo, user);
            if (permitAlienation != null) {
                if (user != null && user.getDsDivisions() != null) {
                    landApplication.setDsDivision(user.getDsDivisions().iterator().next());
                }

              /*  if (user == null) {
                    user = userManager.getUserByUserName("onlineapplicant");
                }*/

                logger.debug("Add land Grant application of land Permit id : {} ,Land Id : {}", permitNo, permitAlienation.getLand().getId());
                alienateGrant(landApplication, permitAlienation, user);
                landApplication.getAlienationDetails().setPermitReference(permitAlienation);

                landApplicationDAO.addLandApplication(landApplication, user);
                logger.debug("Add land Grant application of land application id : {}", landApplication.getId());

                if (landApplication.getDocumentList() != null) {
                    try {
                        documentManagementService.uploadfiles(user, landApplication.getDocumentList(),
                                landApplication.getId());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //update Alienation
                /*permitAlienation.setStatus(Alienation.State.PENDING);*/
                permitAlienation.setBackUpMode(Alienation.BackUpMode.INACTIVE);
                alienationManagementService.updateAlienation(permitAlienation, user);
            }
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getUsername() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addLandDetailApplication(LandApplication landApplication, long landRefNumber, long[] landList, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("Add Detail land application of land application id : {}", landApplication.getId());
            //    long initApplicationId = landApplication.getInitApplicationId();
            // landApplication.setStatus(LandApplication.State.DETAILED_FORM_DATA_ENTRY);

            //find initial land app
            LandApplication initApplication = landApplicationDAO.getLandApplicationByIdUKey(landApplication.getId(), user);

            //set Ds from init Application
            landApplication.setDsDivision(initApplication.getDsDivision());
            landApplication.getHolder().setSlcUser(initApplication.getHolder().getSlcUser());
            landApplication.setInitApplicationId(initApplication.getId());

            resetIdFields(landApplication);

            //update alienation details only if it is a land grant
            if (landApplication.getPreferredAlienationMethod() != null) {
                if (landApplication.getPreferredAlienationMethod().getId() == AppConstants.LAND_GRANT) {
                    alienateGrant(landApplication, initApplication.getAlienationDetails(), user);
                    landApplication.getAlienationDetails().setPermitReference(initApplication.getAlienationDetails().getPermitReference());
                    initApplication.getAlienationDetails().setBackUpMode(Alienation.BackUpMode.INACTIVE);
                } /*else if (landRefNumber != 0) {
                    alienate(landApplication, landRefNumber, landList, user);
                }*/
            }/* else if (landRefNumber != 0) {
                alienate(landApplication, landRefNumber, landList, user);
            }*/

            //add slcUser in Detail Add and Edit


            //initiate workflow  and add new application
            landApplication.setWorkflowItem(workflowService.getWorkflowStartItemById());

            if (landApplication.getHolder() != null && landApplication.getHolder().getChildren() != null && landApplication.getHolder().getChildren().size() > 0) {
                for (Child d : landApplication.getHolder().getChildren()) {
                    d.setId(0);
                }
            }

            if (landApplication.getAlienationMethods() != null &&
                    landApplication.getHolder().getHolderType() == AppConstants.PERSON_APPLICANT) {
                setMarksForLandApplications(landApplication);
            }

            landApplicationDAO.addLandApplication(landApplication, user);


            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("Add Detail land application of land application id : {}", landApplication.getId());

            // close the initial application
            initApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_CLOSED);
            landApplicationDAO.updateLandApplication(initApplication, user);
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    private void resetIdFields(LandApplication landApplication) {
        landApplication.setId(0);
        landApplication.getHolder().setId(0);
        landApplication.getHolder().getContacts().setId(0);
        if (landApplication.getHolder().getContactPerson() != null) {
            landApplication.getHolder().getContactPerson().setId(0);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void editLandDetailApplication(LandApplication landApplication, long landRefNumber, long[] landList, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());

            // landApplication.setStatus(LandApplication.State.DETAILED_FORM_DATA_ENTRY);

            //todo: find ds division from existing app
            /*landApplication.setDsDivision(user.getDsDivisions().iterator().next());*/

            setCommonFields(landApplication, WorkflowTask.DETAILED_FORM_DATA_ENTRY, user);
            landApplication.setWorkflowItem(workflowService.getWorkflowStartItemById());

            if (landApplication.getAlienationMethods() != null &&
                    landApplication.getHolder().getHolderType() == AppConstants.PERSON_APPLICANT) {
                setMarksForLandApplications(landApplication);
            }

            landApplicationDAO.updateLandApplication(landApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    private LandApplication validateWorkflowOfLandApp(long landAppId, WorkflowTask workflowTask, User user) {
        LandApplication existingApplication = getLandApplicationByIdUKey(landAppId, user);
        WorkflowItem workflowItem = workflowService.getNextWorkflowItem(workflowTask,
                existingApplication.getWorkflowItem().getId(), user);
        existingApplication.setWorkflowItem(workflowItem);
        return existingApplication;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void attachLandToApplication(long landApplicationId, long landRefNumber, long[] landList, int alienationType, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            LandApplication existingApplication = validateWorkflowOfLandApp(landApplicationId, WorkflowTask.LAND_ALLOCATED, user);
            try {
                Land land;
                List<Land> landLots = null;
                if (landList != null) {
                    landLots = new ArrayList<Land>();
                    // search Land lots
                    for (long l : landList) {
                        land = new Land();
                        land.setId(l);
                        landLots.add(land);
                    }
                }
                land = landDao.getLandById(landRefNumber);
                AlienationMethod am = alienationManagementService.getAlienationMethodById(alienationType, user);

                if (existingApplication.getAlienationDetails() == null) {

                    logger.debug("Adding new alienation to data base");

                    Alienation alienation = new Alienation();
                    alienation.setReferenceNo("UNKNOWN");
                    alienation.setLand(land);
                    alienation.setLandList(landLots);
                    alienation.setAlienationMethod(am);
                    alienation.setSpouse(existingApplication.getHolder().getSpouse());
                    alienation.setSuccessor(existingApplication.getNominatedSuccessorName());
                    //alienation.setStatus(Alienation.State.ARCHIVED);
                    alienation.setStatus(Alienation.State.PENDING);
                    alienation.setApproveState(Alienation.ApproveState.DATA_ENTRY);
                    alienation.setHolder(existingApplication.getHolder());
                    alienation.getLifeCycleInfo().setCreatedUser(user);
                    alienation.getLifeCycleInfo().setCreatedTimeStamp(new Date());
                    alienation.getLifeCycleInfo().setLastUpdatedUser(user);
                    alienation.getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
                    alienation.setPresident(presidentManagementService.getCurrentPresident().get(0));

                    existingApplication.setAlienationDetails(alienation);

                } else {
                    logger.debug("merge alienation details to data base");
                    existingApplication.getAlienationDetails().setLandList(landLots);
                    existingApplication.getAlienationDetails().setLand(land);
                    existingApplication.getAlienationDetails().setAlienationMethod(am);
                    existingApplication.getAlienationDetails().getLifeCycleInfo().setLastUpdatedUser(user);
                    existingApplication.getAlienationDetails().getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
                }
                landApplicationDAO.updateLandApplication(existingApplication, user);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void acceptAndCompleteAndEditApplication(LandApplication landApplication, long landRefNumber, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("accept and complete and edit land application id : {}", landApplication.getId());

            setCommonFields(landApplication, WorkflowTask.ACCEPTED_AND_COMPLETED, user);

            setApprovalComment(landApplication, comment, "", user);

            //backups the old application

            backupLandApplication(landApplication, LandApplication.State.COMPLETED_APPLICATION_ARCHIVED, user);

            landApplicationDAO.updateLandApplication(landApplication, user);

            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean backupLandApplication(LandApplication currentApplication, LandApplication.State backupState, User user) {
        //backups the old application
        try {
            LandApplication existingApplication = getLandApplicationByIdUKey(currentApplication.getId(), user);
            if (existingApplication != null) {
                Alienation existingAlienation = existingApplication.getAlienationDetails();

                LandApplication newApplication = getApplicationDetails(existingApplication);

                //set the New holder to backup
                newApplication.setHolder(getHolderDetail(existingApplication));

                newApplication.setInitApplicationId(existingApplication.getId());
                newApplication.setAlienationDetails(existingAlienation);

                //newApplication.setInitialStatus(LandApplication.State.COMPLETED_APPLICATION_ARCHIVED);
                newApplication.setInitialStatus(backupState);

                landApplicationDAO.addLandApplication(newApplication, user);
                return true;
            } else {
                //Invalid Land Application
                return false;
            }


        } catch (Exception e) {
            logger.debug("Error in Backup Land Application State :{}  Error :{}", backupState, e);
            e.printStackTrace();
            return false;
        }


    }

    private Holder getHolderDetail(LandApplication application) {
        Holder holder = new Holder();

        holder.setHolderType(application.getHolder().getHolderType());
        holder.setName(application.getHolder().getName());
        holder.setAnnualIncome(application.getHolder().getAnnualIncome());
        holder.setChildren(application.getHolder().getChildren());
        holder.setContactPerson(application.getHolder().getContactPerson());
        holder.setContacts(application.getHolder().getContacts());
        holder.setDateOfBirth(application.getHolder().getDateOfBirth());
        holder.setDesignation(application.getHolder().getDesignation());
        holder.setGender(application.getHolder().getGender());
        holder.setGnDivision(application.getHolder().getGnDivision());
        holder.setLocalAuthority(application.getHolder().getLocalAuthority());
        holder.setNameOfHead(application.getHolder().getNameOfHead());
        holder.setRegistrationNumberOrNIC(application.getHolder().getRegistrationNumberOrNIC());
        holder.setSpouse(application.getHolder().getSpouse());
        holder.setNationality(application.getHolder().isNationality());
        holder.setSlcUser(application.getHolder().getSlcUser());

        return holder;
    }

    private LandApplication getApplicationDetails(LandApplication application) {

        LandApplication landApplication = new LandApplication();

        landApplication.setWorkflowItem(null);
        landApplication.setSubmitDate(application.getSubmitDate());
        landApplication.setLandUsage(application.getLandUsage());
        landApplication.setAlienationDetails(application.getAlienationDetails());

        //landApplication.setAlienationMethods(application.getAlienationMethods());
        List<AlienationMethod> alienationMethodsNew = new ArrayList<AlienationMethod>();
        for (AlienationMethod a : application.getAlienationMethods()) {
            alienationMethodsNew.add(a);
        }
        landApplication.setAlienationMethods(alienationMethodsNew);

        //landApplication.setDsDivisions(application.getDsDivisions());
        Set<DSDivision> dsDivisionsNew = new HashSet<DSDivision>();
        for (DSDivision ds : application.getDsDivisions()) {
            dsDivisionsNew.add(ds);
        }
        landApplication.setDsDivisions(dsDivisionsNew);

        //landApplication.setLandList(application.getLandList());
        List<Land> landListNew = new ArrayList<Land>();
        for (Land land : application.getLandList()) {
            landListNew.add(land);
        }
        landApplication.setLandList(landListNew);


        landApplication.setDsDivision(application.getDsDivision());
        landApplication.setHolder(application.getHolder());
        landApplication.setLandExpectedExtent(application.getLandExpectedExtent());
        landApplication.setNominatedSuccessorName(application.getNominatedSuccessorName());
        landApplication.setPresentUserName(application.getPresentUserName());
        landApplication.setDevelopmentStatus(application.getDevelopmentStatus());
        landApplication.setPermitHolderOccupiedTheLand(application.isPermitHolderOccupiedTheLand());
        landApplication.setPurpose(application.getPurpose());
        landApplication.setPreferredAlienationMethod(application.getPreferredAlienationMethod());
        landApplication.setInitialStatus(application.getInitialStatus());
        landApplication.setInitApplicationId(application.getInitApplicationId());
        landApplication.setAnnualIncome(application.getAnnualIncome());
        landApplication.setOccupation(application.getOccupation());
        landApplication.setInformationAboutTheProject(application.getInformationAboutTheProject());
        landApplication.setComment(application.getComment());
        landApplication.setPlanNo(application.getPlanNo());
        landApplication.setLotNo(application.getLotNo());
        landApplication.setNoOfDependents(application.getNoOfDependents());
        landApplication.setDurationOfResidency(application.getDurationOfResidency());
        landApplication.setHeritageOrLegallyDeservedLand(application.isHeritageOrLegallyDeservedLand());
        landApplication.setSpecialStrengths(application.getSpecialStrengths());
        landApplication.setAbilityToDevelopTheLand(application.getAbilityToDevelopTheLand());
        landApplication.setSocialActivities(application.getSocialActivities());
        landApplication.setCivilStatus(application.getCivilStatus());
        landApplication.setResidencialType(application.getResidencialType());
        landApplication.setMarks(application.getMarks());
        landApplication.setLegallyDeservedProperty(application.isLegallyDeservedProperty());
        landApplication.setDocumentList(application.getDocumentList());
        landApplication.setRefNumber(application.getRefNumber());
        landApplication.setAgreementNo(application.getAgreementNo());
        landApplication.setObjections(application.getObjections());
        landApplication.setCommunicationMethod(application.getCommunicationMethod());
        landApplication.setCommunicationLanguage(application.getCommunicationLanguage());
        landApplication.setDueDate(application.getDueDate());
        landApplication.setLetterCount(application.getLetterCount());

        return landApplication;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void acceptAndCompleteApplication(LandApplication landApplication, long landRefNumber, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("accept and complete land application id : {}", landApplication.getId());

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.ACCEPTED_AND_COMPLETED,
                    existingApplication.getWorkflowItem().getId(), user));

            setApprovalComment(existingApplication, comment, "", user);

            landApplicationDAO.updateLandApplication(existingApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }

        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectAndCompleteApplication(LandApplication landApplication, long landRefNumber, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("reject and complete land application id : {}", landApplication.getId());
            // setCommonFields(landApplication, WorkflowTask.REJECTED_AND_ARCHIVED, user);

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.REJECTED_AND_ARCHIVED,
                    existingApplication.getWorkflowItem().getId(), user));

            setApprovalComment(existingApplication, comment, "", user);

            /*if (landRefNumber != 0) {
                //todo: Verify entries are removed from alienation table and other childs such as lots
                existingApplication.setAlienationDetails(null);
            }*/

            landApplicationDAO.updateLandApplication(existingApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }

        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void notReceivedCompleteApplication(LandApplication landApplication, long landRefNumber, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("the completed land application not submitted by applicant -  id : {}", landApplication.getId());
            //setCommonFields(landApplication, WorkflowTask.NOT_SUBMITTED_AND_ARCHIVED, user); kk
            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.NOT_SUBMITTED_AND_ARCHIVED,
                    existingApplication.getWorkflowItem().getId(), user));

            setApprovalComment(existingApplication, comment, "", user);

            /*if (landRefNumber != 0) {
                logger.debug("land lot list size {}", landList.length);
                //todo: Verify entries are removed from alienation table and other childs such as lots
                landApplication.setAlienationDetails(null);
            }*/

            landApplicationDAO.updateLandApplication(existingApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }

        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveAttachedLand(LandApplication landApplication, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());


            //landApplication.setWorkflowTask(WorkflowTask.COMPLETED);

            //todo: find ds division from existing app

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            //////////
            //  existingApplication.setStatus(LandApplication.State.LAND_ALLOCATION_APPROVED);
            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.LAND_ALLOCATION_APPROVED,
                    existingApplication.getWorkflowItem().getId(), user));
            //////////
            //existingApplication.setComment(landApplication.getComment());
            setApprovalComment(existingApplication, comment, AppConstants.APPROVE, user);

            //   landApplication.setDsDivision(existingApplication.getDsDivision());

            // landApplication.setAlienationDetails(existingApplication.getAlienationDetails());
            //   landApplication.getLifeCycleInfo().setCreatedTimeStamp(existingApplication.getLifeCycleInfo().getCreatedTimeStamp());
            //  landApplication.getLifeCycleInfo().setCreatedUser(existingApplication.getLifeCycleInfo().getCreatedUser());

            /*  if (landRefNumber != 0) {
                logger.debug("land lot list size {}", landList.length);
                alienate(landApplication, landRefNumber, landList, user);
            }*/

            landApplicationDAO.updateLandApplication(existingApplication, user);

            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            //logger.debug("Approval of Land application of land application id : {} holder: {}", landApplication.getId(),landApplication.getHolder().getName());
            Holder holder = existingApplication.getHolder();
            String message = "Your land application with reference no: " + existingApplication.getHolder().getSlcUser().getUsername() + " has been approved for land allocation.";
            smsSenderService.sendSmsToHolder(holder, message);
            logger.debug("Approval of Land application of land application id : {} holder: {}", landApplication.getId());
            logger.debug("Approval of Land application of land application id : {} holder: {}", existingApplication.getId(), existingApplication.getHolder().getName());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectAttachedLand(LandApplication landApplication, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("reject Attached Land of land application id : {}", landApplication.getId());

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);
            //   existingApplication.setStatus(LandApplication.State.LAND_ALLOCATION_REJECTED);

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.LAND_ALLOCATION_REJECTED,
                    existingApplication.getWorkflowItem().getId(), user));

            /*if(existingApplication.getComment()!=null){
               existingApplication.setComment(existingApplication.getComment() + " \n" + landApplication.getComment());
                logger.debug("Rej existingComment 1 : {}", existingApplication.getComment());
                logger.debug("Rej Comment 2 : {}", landApplication.getComment());
            }else{
                existingApplication.setComment(landApplication.getComment());
            }*/
            logger.debug("Rej Comment : {}", landApplication.getComment());
            //existingApplication.setComment(landApplication.getComment());
            setApprovalComment(existingApplication, comment, AppConstants.REJECTE, user);

            landApplicationDAO.updateLandApplication(existingApplication, user);

            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("reject Attached Land of land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to reject land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveAttachedAlienationDoc(LandApplication landApplication, int isSign, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("Attach Alienation Doc land application id : {}", landApplication.getId());


            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);
            if (isSign == 1) {
                //existingApplication.setStatus(LandApplication.State.SIGNED_PRINTED_ALIENATION_DOCUMENT);
                existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.SIGNED_PRINTED_ALIENATION_DOCUMENT,
                        existingApplication.getWorkflowItem().getId(), user));

            } else {
                //  existingApplication.setStatus(LandApplication.State.UNSIGNED_PRINTED_ALIENATION_DOCUMENT);
                existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.UNSIGNED_PRINTED_ALIENATION_DOCUMENT,
                        existingApplication.getWorkflowItem().getId(), user));
            }

            if (landApplication.getComment() != null) {
                existingApplication.setComment(landApplication.getComment());
            }

            landApplicationDAO.updateLandApplication(existingApplication, user);

            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("save Attached Alienation Doc land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void interviewLandDetailApplication(LandApplication landApplication, long landRefNumber, long[] landList, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("interview land application of land application id : {}", landApplication.getId());
            //todo: archived old app
            // landApplication.setStatus(LandApplication.State.INTERVIEW_DATA_ENTRY);


            //  landApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.INTERVIEW_DATA_ENTRY,
            //     landApplication.getWorkflowItem().getId(), user));


            setCommonFields(landApplication, WorkflowTask.INTERVIEW_DATA_ENTRY, user);
            /*//todo: find ds division from existing app
            landApplication.setDsDivision(user.getDsDivisions().iterator().next());

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            // landApplication.setAlienationDetails(existingApplication.getAlienationDetails());
            landApplication.getLifeCycleInfo().setCreatedTimeStamp(existingApplication.getLifeCycleInfo().getCreatedTimeStamp());
            landApplication.getLifeCycleInfo().setCreatedUser(existingApplication.getLifeCycleInfo().getCreatedUser());
*/
            landApplicationDAO.updateLandApplication(landApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void interviewCompleteLandDetailApplication(LandApplication landApplication, long landRefNumber,
                                                       long[] landList, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("interview completed Detail land application of land application id : {}", landApplication.getId());

            //set Common Details
            setCommonFields(landApplication, WorkflowTask.INTERVIEW_COMPLETED, user);

            //todo: find ds division from existing app or keep as hidden field

            landApplicationDAO.updateLandApplication(landApplication, user);

            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("edit Detail land application of land application id : {}", landApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void handleObjections(LandApplication landApplication, String comment, String objections, WorkflowTask workflowTask, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("objection handling -  by {}", user.getUsername());
            //todo: archived old app

            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

            setApprovalComment(existingApplication, comment, AppConstants.SAVE_OBJECTION, user);

            //set Objection
            setObjections(existingApplication, objections, user);

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(workflowTask,
                    existingApplication.getWorkflowItem().getId(), user));
            //existingApplication.setObjections(landApplication.getObjections());

            //todo: find ds division from existing app or keep as hidden field

            landApplicationDAO.updateLandApplication(existingApplication, user);
            logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), existingApplication.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }
            logger.debug("edit Detail land application of land application id : {}", existingApplication.getId());
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void finalizeApplication(LandApplication landApplication, String comment, User user) {
        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            logger.debug("objection handling -  land application id : {}", landApplication.getId());
            LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);
            //existingApplication.setComment(landApplication.getComment());
            setApprovalComment(existingApplication, comment, AppConstants.FINALIZE_AS_NO_OBJECTION, user);

            if (existingApplication.getPreferredAlienationMethod() != null) {
                if (existingApplication.getPreferredAlienationMethod().getId() == AppConstants.LAND_GRANT) {
                    //  existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.LAND_ALLOCATION_APPROVED,
                    //  existingApplication.getWorkflowItem().getId(), user));

                    //WorkflowTask.LAND_ALLOCATION_APPROVED
                    existingApplication.setWorkflowItem(workflowService.getWorkflowItemById(AppConstants.LAND_ALLOCATION_APPROVED));
                    landApplicationDAO.updateLandApplication(existingApplication, user);
                    return;
                }
            }

            existingApplication.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.DETAILED_FORM_FINALIZED,
                    existingApplication.getWorkflowItem().getId(), user));
            landApplicationDAO.updateLandApplication(existingApplication, user);
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to add land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateInitialLandApplication(LandApplication landApplication, User user) {
        /*  if (user.isAuthorized(Permission.MANAGE_INITIAL_LAND_APPLICATION) ||
    user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {   */
        if (landApplication.getInitApplicationId() > 0) {
            // landApplication.setStatus(LandApplication.State.DETAILED_FORM_DATA_ENTRY);
            landApplication.setWorkflowItem(workflowService.getWorkflowStartItemById());
        } else {
            landApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);
        }

        landApplication.getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
        landApplication.getLifeCycleInfo().setLastUpdatedUser(user);

        LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);
        landApplication.getLifeCycleInfo().setCreatedTimeStamp(existingApplication.getLifeCycleInfo().getCreatedTimeStamp());
        landApplication.getLifeCycleInfo().setCreatedUser(existingApplication.getLifeCycleInfo().getCreatedUser());
        landApplication.setDsDivision(existingApplication.getDsDivision());

        if (landApplication.getPreferredAlienationMethod() != null) {
            if (landApplication.getPreferredAlienationMethod().getId() == AppConstants.LAND_GRANT) {
                landApplication.setAlienationDetails(existingApplication.getAlienationDetails());
                landApplication.getAlienationDetails().setPermitReference(existingApplication.getAlienationDetails().getPermitReference());
            }
        }

        /* Set marks for the land application */
        if (landApplication.getAlienationMethods() != null &&
                landApplication.getHolder().getHolderType() == AppConstants.PERSON_APPLICANT) {
            setMarksForLandApplications(landApplication);
        }

        landApplicationDAO.updateLandApplication(landApplication, user);
        logger.debug("landApplication.getDocumentList:{}", landApplication.getDocumentList());
        if (landApplication.getDocumentList() != null) {
            try {
                logger.debug("Uploading files");
                documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApplication.getId());
            } catch (Exception e) {
                logger.debug("Error :{}", e);
            }
        }
        logger.debug("Update land application of land application id : {}", landApplication.getId());
        /*  } else {
         logger.debug("No permission");
         handleELandRuntimeException(user.getUsername() + " doesn't have permission to Update land Application",
             ErrorCodes.UNAUTHORIZED_ACCESS);
     }   */
    }

    //update the alienation of the land application when land or
    //land list have been associated to the land application
    private void alienateGrant(LandApplication landApplication, Alienation permitAlienation, User user) {
        try {

            logger.debug("Alienate Grant landApplication id - {} ", landApplication.getId());
            //TODO: remove this

            if (landApplication.getAlienationDetails() == null) {

                logger.debug("Adding new alienation to data base");

                Alienation alienation = new Alienation();
                alienation.setReferenceNo("UNKNOWN");
                alienation.setLand(permitAlienation.getLand());
                alienation.setAlienationMethod(landApplication.getPreferredAlienationMethod());
                alienation.setSpouse(landApplication.getHolder().getSpouse());
                alienation.setSuccessor(landApplication.getNominatedSuccessorName());
                //alienation.setStatus(Alienation.State.ARCHIVED);
                alienation.setStatus(Alienation.State.PENDING);
                alienation.setApproveState(Alienation.ApproveState.DATA_ENTRY);
                alienation.setHolder(landApplication.getHolder());
                alienation.getLifeCycleInfo().setCreatedUser(user);
                alienation.getLifeCycleInfo().setCreatedTimeStamp(new Date());
                alienation.getLifeCycleInfo().setLastUpdatedUser(user);
                alienation.getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
                alienation.setPresident(presidentManagementService.getCurrentPresident().get(0));

                landApplication.setAlienationDetails(alienation);

            } else {
                logger.debug("merge alienation details to data base");
                landApplication.getAlienationDetails().setLand(permitAlienation.getLand());
                landApplication.getAlienationDetails().getLifeCycleInfo().setLastUpdatedUser(user);
                landApplication.getAlienationDetails().getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void completeLandApplication(long applicationId, User user) {
        //TODO: complete in a view page with comments and attachments
        LandApplication landApp = getLandApplicationByIdUKey(applicationId, user);
        //general state is completed not the work flow state and remove from work bench once completed
        //landApp.setWorkflowTask(WorkflowTask.COMPLETED);
        //landApp.setStatus(LandApplication.State.DETAILED_FORM_FINALIZED);
        landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.DETAILED_FORM_FINALIZED,
                landApp.getWorkflowItem().getId(), user));

        landApplicationDAO.updateLandApplication(landApp, user);
        logger.debug("Update land application of land application id : {}", landApp.getId());
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public LandApplication getLandApplicationByIdUKey(long id, User user) {
        LandApplication landApp = landApplicationDAO.getLandApplicationByIdUKey(id, user);
        //  setButtonAction(landApp.getWorkflowItem(), user);
        logger.debug("Land application id : {}", landApp.getId());
        landApp.getHolder().setChildren(landApp.getHolder().getChildren());
        for (Child c : landApp.getHolder().getChildren()) {
            logger.debug(c.getFullName());
        }
        if (landApp.getAlienationDetails() != null) {
            landApp.getAlienationDetails().getLand().setId(landApp.getAlienationDetails().getLand().getId());
        }

        if (landApp.getWorkflowItem() != null) {
            landApp.setNextAction(setButtonAction(landApp.getWorkflowItem(), user));
        }
        return landApp;
    }

    public int setButtonAction(WorkflowItem workflowItem, User user) {

        WorkflowItem nextWorkflowItem = workflowService.getNextWorkflowItemByUserRole(workflowItem.getId(), user);
        //todo move to service and use workflow service
        //todo:  and iterate next itm list and find the relevant item and pick strut action and lable to set the buttons dynamically

        if (nextWorkflowItem != null) {

            if (nextWorkflowItem.getWorkflowTask() == WorkflowTask.APPROVED ||
                    nextWorkflowItem.getWorkflowTask() == WorkflowTask.FULLY_APPROVED) {

                if (workflowItem.getId() == AppConstants.ORLP_APPROVED) {
                    return 2; // only the recommend allow. No reject
                }
                return 1;
            }
        }
        return 0;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getPendingApprovalInitLandApplicationList(User user) {
        //todo Validate the user
        logger.info("Filter Init Land Application List To be Approved");
        List<LandApplication> landApplicationList = landApplicationDAO.getRankedApplicationsByState(user,
                LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);
        logger.debug("size :{}", landApplicationList.size());
        return landApplicationList;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getPendingEditInitLandApplicationList(User user) {
        //todo Validate the user
        logger.info("Filter Init Land Application List To be Approved");
        List<LandApplication> landApplicationList = landApplicationDAO.getInitialApplicationsByState(user,
                LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);
        if (landApplicationList == null) {
            landApplicationList = landApplicationDAO.getInitialApplicationsByState(user,
                    LandApplication.State.INITIAL_APPLICATION_REJECTED);
        } else {
            List<LandApplication> landApplicationListRejected = landApplicationDAO.getInitialApplicationsByState(user,
                    LandApplication.State.INITIAL_APPLICATION_REJECTED);
            for (LandApplication a : landApplicationListRejected) {
                landApplicationList.add(a);
            }
        }

        logger.debug("size :{}", landApplicationList.size());
        return landApplicationList;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getPendingApprovalDetailLandApplicationList(User user) {
        //todo Validate the user
        logger.info("Filter Init Land Application List To be Approved");
        EnumSet<WorkflowTask> stateSet = EnumSet.of(WorkflowTask.DETAILED_FORM_DATA_ENTRY,
                WorkflowTask.DETAILED_FORM_REJECTED);
        List<LandApplication> landApplicationList = landApplicationDAO.getApplicationsByStates(user, stateSet);

        logger.debug("size :{}", landApplicationList.size());
        return landApplicationList;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Map<String, String> approveInitLandApplication(long applicationId, String comment, User user) {
        Map<String, String> slcMessages = null;

        LandApplication landApplication = getLandApplicationByIdUKey(applicationId, user);
        //landApplication.setComment(comment);
        if (user.isAuthorized(Permission.APPROVE_REJECT_INITIAL_LAND_APPLICATION)) {
            landApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_APPROVED);

            //set The Initial RefNo
            // landApplication.setRefNumber("ILA/" + new Date().getYear() + "/" + landApplication.getId());
            landApplication.setRefNumber(AppConstants.INITIAL_APP_PRIFIX + "/" + landApplication.getDsDivision().getEnDivisionName().substring(0, 4).toUpperCase() + "/" + landApplication.getId());
            logger.debug("Initial RefNo : {}", landApplication.getRefNumber());

            //set Approval Comment
            setApprovalComment(landApplication, comment, AppConstants.APPROVE, user);

            landApplicationDAO.updateLandApplication(landApplication, user);

            // Notification of land alienation application approval to all LOs

            String emailSubject = "Initial Land Application Approval";
            String emailedMessage = "The initial land application of " + landApplication.getHolder().getName() + " which is referenced by number : " + landApplication.getRefNumber() + " has been approved by ";
            Set<DSDivision> dsDivs = user.getDsDivisions();
            List<String> roles = new ArrayList<String>();
            roles.add("LO");

            //create SLC user
            slcMessages = createSLCUser(landApplication, user);
            mailSenderService.notifyToAll(dsDivs, roles, user, emailSubject, emailedMessage);

        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getUsername() +
                    "Doesn't have permission to approve initial  land Application", ErrorCodes.UNAUTHORIZED_ACCESS);
        }

        if (slcMessages == null) {
            slcMessages = new TreeMap<String, String>();
        }

        String refNumber = landApplication.getRefNumber();
        slcMessages.put("slcReferenceNo", refNumber);
        smsSenderService.notifyBySms(user.getDsDivisions(), user, landApplication.getRefNumber() + " Approved");

        return slcMessages;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveDetailedLandApplication(long id, String comment, User user) {
        LandApplication landApp = getLandApplicationByIdUKey(id, user);
        if (landApp != null) {
            //setComment
            setApprovalComment(landApp, comment, AppConstants.APPROVE, user);

            if (landApp.getPreferredAlienationMethod() != null) {
                if (landApp.getPreferredAlienationMethod().getId() == AppConstants.LAND_GRANT) {

                    //WorkflowTask.LAND_ALLOCATION_APPROVED
                    // landApp.setWorkflowItem(workflowService.getWorkflowItemById(AppConstants.LAND_ALLOCATION_APPROVED)); kk
                    // approve byPassing
                    landApp.setWorkflowItem(workflowService.getWorkflowItemById(40));

                    landApp.setRefNumber(AppConstants.DETAILED_APP_PRIFIX + "/" + landApp.getDsDivision().getEnDivisionName().substring(0, 4).toUpperCase() + "/" + landApp.getId());
                    logger.debug("Detail RefNo : {}", landApp.getRefNumber());
                    landApplicationDAO.updateLandApplication(landApp, user);
                    return;
                }
            }

            //landApp.setComment(comment);
            //  landApp.setStatus(LandApplication.State.DETAILED_FORM_APPROVED);
            landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.DETAILED_FORM_APPROVED,
                    landApp.getWorkflowItem().getId(), user));
            landApp.setRefNumber(AppConstants.DETAILED_APP_PRIFIX + "/" + landApp.getDsDivision().getEnDivisionName().substring(0, 4).toUpperCase() + "/" + landApp.getId());
            logger.debug("Detail RefNo : {}", landApp.getRefNumber());


            //To update the SLC usere's email if an email address is available for the applicant at this stage.
            String email = landApp.getHolder().getContacts().getEmail();

            if (email != null && !email.isEmpty()) {
                landApp.getHolder().getSlcUser().setEmail(email);
                landApp.getHolder().getSlcUser().getLifeCycleInfo().setLastUpdatedUser(user);
                landApp.getHolder().getSlcUser().getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
            }

            landApplicationDAO.updateLandApplication(landApp, user);

            String emailSubject = "Detailed Land Application Approval";
            String emailedMessage = "The detailed land application of " + landApp.getHolder().getName() + " which is referenced by number : " + landApp.getRefNumber() + " has been approved by ";
            Set<DSDivision> dsDivs = user.getDsDivisions();
            List<String> roles = new ArrayList<String>();
            roles.add("LO");
            mailSenderService.notifyToAll(dsDivs, roles, user, emailSubject, emailedMessage);

            //Set<DSDivision> dsDivs = landApp.getDsDivisions();
            //mailSenderService.notifyToAll(dsDivs,user,landApp.getRefNumber()+" Approved");
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveObjections(LandApplication landApplication, String comment, WorkflowTask workflowTask, User user) {
        //todo : check permission
        LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);
        if (landApp != null) {
            // landApp.setStatus(LandApplication.State.OBJECTION_HANDLING_APPROVED);
            //landApp.setComment(landApplication.getComment());
            setApprovalComment(landApp, comment, AppConstants.APPROVE, user);

            landApp.setWorkflowItem(workflowService.getNextWorkflowItem(workflowTask,
                    landApp.getWorkflowItem().getId(), user));
            landApplicationDAO.updateLandApplication(landApp, user);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveCompletedApplication(LandApplication landApplication, String comment, User user) {
        LandApplication existingLandApp = getLandApplicationByIdUKey(landApplication.getId(), user);
        if (existingLandApp != null) {
            WorkflowItem nextNode = null;
            // if (landApp.getStatus() == LandApplication.State.ACCEPTED_AND_COMPLETED) {
            //landApp.setStatus(LandApplication.State.APPROVE_ACCEPTED_AND_COMPLETED_APPLICATION);
            // landApp.setWorkflowTask(WorkflowTask.COMPLETED);
            // WorkflowItem startNode = workflowService.getStartItemOfWorkflow(landApp.getAlienationMethod().getId());
            //find workflow item by workfow id, role and task

            int alienationMethod = existingLandApp.getAlienationDetails().getAlienationMethod().getId();
            if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.ACCEPTED_AND_COMPLETED ||
                    existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.REJECTED) {
                if (alienationMethod == AppConstants.LONG_TERM_LEASE) {
                    //todo : refactore  remove this code

                    nextNode = workflowService.getWorkflowItemById(30);
                } else if (alienationMethod == AppConstants.LAND_GRANT) {
                    nextNode = workflowService.getWorkflowItemById(40);
                } else if (alienationMethod == AppConstants.RELEASING_TO_DEPARTMENTS) {
                    nextNode = workflowService.getWorkflowItemById(50);
                } else if (alienationMethod == AppConstants.VESTING_ORDER) {
                    nextNode = workflowService.getWorkflowItemById(60);
                } else if (alienationMethod == AppConstants.SPECIAL_GRANT) {
                    nextNode = workflowService.getWorkflowItemById(70);
                } else if (alienationMethod == AppConstants.LAND_PERMIT) {
                    nextNode = workflowService.getWorkflowItemById(80);
                } else if (alienationMethod == AppConstants.SHORT_TERM_LEASE) {
                    nextNode = workflowService.getWorkflowItemById(90);
                } else {
                    nextNode = workflowService.getNextWorkflowItem(WorkflowTask.ACCEPTED_AND_COMPLETED_APPLICATION_APPROVED,
                            existingLandApp.getWorkflowItem().getId(), user);
                }
            } else if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.REJECTED_AND_ARCHIVED) {
                //landApp.setStatus(LandApplication.State.APPROVE_REJECTED_AND_ARCHIVED_APPLICATION);
                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.REJECTED_AND_ARCHIVED_APPLICATION_APPROVED,
                        existingLandApp.getWorkflowItem().getId(), user);

                //release the allocation of land
                Alienation rejectAlienation = existingLandApp.getAlienationDetails();
                rejectAlienation.setStatus(Alienation.State.ARCHIVED);
                existingLandApp.setAlienationDetails(rejectAlienation);


            } else if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.NOT_SUBMITTED_AND_ARCHIVED) {

                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.APPROVE_NOT_SUBMITTED_APPLICATION,
                        existingLandApp.getWorkflowItem().getId(), user);
                // landApp.setStatus(LandApplication.State.APPROVE_NOT_SUBMITTED_APPLICATION);

                //release the allocation of land
                Alienation rejectAlienation = existingLandApp.getAlienationDetails();
                rejectAlienation.setStatus(Alienation.State.ARCHIVED);
                existingLandApp.setAlienationDetails(rejectAlienation);
            }

            /*  //todo if not null
                        if (nextNode != null) {
                            if (!nextNode.getUserRole().contains(user.getRole().getId())) {
                                //todo : handle authorization exception
                            }

                            if (!nextNode.getAlienationMethod().contains(existingLandApp.getAlienationMethod().getId() + "")) {
                                //todo : //you can not perform this action under this alienation method
                            }
                        }
            */
            existingLandApp.setWorkflowItem(nextNode);
            setApprovalComment(existingLandApp, comment, AppConstants.APPROVE, user);

            landApplicationDAO.updateLandApplication(existingLandApp, user);
            //upload file
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), existingLandApp.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }

        }
    }

    //ByPass the user completion land
    @Transactional(propagation = Propagation.REQUIRED)
    public void approveLandAllocationWithByPass(LandApplication landApplication, String comment, User user) {
        LandApplication existingLandApp = getLandApplicationByIdUKey(landApplication.getId(), user);
        if (existingLandApp != null) {
            WorkflowItem nextNode = null;

            int alienationMethod = existingLandApp.getAlienationDetails().getAlienationMethod().getId();
            if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.LAND_ALLOCATED) {
                if (alienationMethod == AppConstants.LONG_TERM_LEASE) {
                    nextNode = workflowService.getWorkflowItemById(30);
                } else if (alienationMethod == AppConstants.LAND_GRANT) {
                    nextNode = workflowService.getWorkflowItemById(40);
                } else if (alienationMethod == AppConstants.RELEASING_TO_DEPARTMENTS) {
                    nextNode = workflowService.getWorkflowItemById(50);
                } else if (alienationMethod == AppConstants.VESTING_ORDER) {
                    nextNode = workflowService.getWorkflowItemById(60);
                } else if (alienationMethod == AppConstants.SPECIAL_GRANT) {
                    nextNode = workflowService.getWorkflowItemById(70);
                } else if (alienationMethod == AppConstants.LAND_PERMIT) {
                    nextNode = workflowService.getWorkflowItemById(80);
                } else if (alienationMethod == AppConstants.SHORT_TERM_LEASE) {
                    nextNode = workflowService.getWorkflowItemById(90);
                } else {
                    nextNode = workflowService.getNextWorkflowItem(WorkflowTask.ACCEPTED_AND_COMPLETED_APPLICATION_APPROVED,
                            existingLandApp.getWorkflowItem().getId(), user);
                }

                existingLandApp.setWorkflowItem(nextNode);
                setApprovalComment(existingLandApp, comment, AppConstants.APPROVE, user);

                landApplicationDAO.updateLandApplication(existingLandApp, user);
                //upload file
                if (landApplication.getDocumentList() != null) {
                    try {
                        logger.debug("Uploading files");
                        logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                        documentManagementService.uploadfiles(user, landApplication.getDocumentList(), existingLandApp.getId());
                    } catch (Exception e) {
                        logger.debug("Error :{}", e);
                    }
                }

            }

        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectCompletedApplicationByDS(LandApplication landApplication, String comment, User user) {
        LandApplication existingLandApp = getLandApplicationByIdUKey(landApplication.getId(), user);
        if (existingLandApp != null) {
            WorkflowItem nextNode = null;

            if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.ACCEPTED_AND_COMPLETED) {

                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.ACCEPTED_AND_COMPLETED_APPLICATION_REJECTED,
                        existingLandApp.getWorkflowItem().getId(), user);

            } else if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.REJECTED_AND_ARCHIVED) {

                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.REJECT_REJECTED_AND_ARCHIVED_APPLICATION,
                        existingLandApp.getWorkflowItem().getId(), user);

            } else if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.NOT_SUBMITTED_AND_ARCHIVED) {

                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.REJECT_NOT_SUBMITTED_APPLICATION,
                        existingLandApp.getWorkflowItem().getId(), user);

            } else if (existingLandApp.getWorkflowItem().getWorkflowTask() == WorkflowTask.REJECTED) {

                nextNode = workflowService.getNextWorkflowItem(WorkflowTask.ACCEPTED_AND_COMPLETED_APPLICATION_REJECTED,
                        existingLandApp.getWorkflowItem().getId(), user);

            }

            existingLandApp.setLetterCount(0);
            existingLandApp.setWorkflowItem(nextNode);
            setApprovalComment(existingLandApp, comment, AppConstants.REJECTED, user);

            landApplicationDAO.updateLandApplication(existingLandApp, user);
            //upload file
            if (landApplication.getDocumentList() != null) {
                try {
                    logger.debug("Uploading files");
                    logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                    documentManagementService.uploadfiles(user, landApplication.getDocumentList(), existingLandApp.getId());
                } catch (Exception e) {
                    logger.debug("Error :{}", e);
                }
            }

        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectDetailedLandApplication(long id, String comment, User user) {
        LandApplication landApp = getLandApplicationByIdUKey(id, user);
        if (landApp != null) {
            //set Comment
            setApprovalComment(landApp, comment, AppConstants.REJECTE, user);

            //  landApp.setComment(comment);
            //   landApp.setStatus(LandApplication.State.DETAILED_FORM_REJECTED);
            landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.DETAILED_FORM_REJECTED,
                    landApp.getWorkflowItem().getId(), user));

            landApp.setRefNumber(AppConstants.DETAILED_APP_PRIFIX + "/" + landApp.getDsDivision().getEnDivisionName().substring(0, 4).toUpperCase() + "/" + landApp.getId());
            logger.debug("Detail RefNo : {}", landApp.getRefNumber());
            landApplicationDAO.updateLandApplication(landApp, user);

            String emailSubject = "Detailed Land Application Rejection";
            String emailedMessage = "The detailed land application of " + landApp.getHolder().getName() + " which is referenced by number : " + landApp.getRefNumber() + " has been rejected by ";
            Set<DSDivision> dsDivs = user.getDsDivisions();
            List<String> roles = new ArrayList<String>();
            roles.add("LO");
            mailSenderService.notifyToAll(dsDivs, roles, user, emailSubject, emailedMessage);

            //Set<DSDivision> dsDivs = landApp.getDsDivisions();
            //mailSenderService.notifyToAll(dsDivs,user,landApp.getRefNumber()+" Rejected");
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveLandApplication(LandApplication landApplication, String comment, User user) {
        //TODO : check permission
        LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);

        if (landApp != null) {

            WorkflowItem nextItem = workflowService.getNextWorkflowItemByUserRole(landApp.getWorkflowItem().getId(), user);

            if (nextItem != null) {    //if forward state available
                logger.debug("Next item - id ------------------------------ : {}", nextItem.getId());
                //logger.debug("Next item - Action : {}", nextItem.getAction());
                logger.debug("Next item - User Role : {}", nextItem.getUserRole());
                // landApp.setWorkflowTask(nextItem); //set to workflow state of approve
                landApp.setWorkflowItem(nextItem); //set to workflow state of approve
                //WorkflowTask finalItem = landApp.findForwardState();
                // int finalItemId = landApp.getWorkflowItem().getRejectItemId();
                // WorkflowItem finalItem = workflowService.getWorkflowItemById(finalItemId);

                // if (finalItem == null) {
                //   landApp.setStatus(LandApplication.State.FULLY_APPROVED);
                //  }
                setApprovalComment(landApp, comment, AppConstants.APPROVE, user);

                landApplicationDAO.updateLandApplication(landApp, user);

                //upload file
                if (landApplication.getDocumentList() != null) {
                    try {
                        logger.debug("Uploading files");
                        logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                        documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApp.getId());
                    } catch (Exception e) {
                        logger.debug("Error :{}", e);
                    }
                }
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void approveLandApplicationByLC(LandApplication landApplication, WorkflowTask task, String comment, User user) {
        LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);

        if (landApp != null) {

            WorkflowItem nextItem = workflowService.getNextWorkflowItem(task,
                    landApp.getWorkflowItem().getId(), user);

            if (nextItem != null && nextItem.getUserRole().equals(user.getRole().getId())) {    //if forward state available
                logger.debug("Next item - id ------------------------------ : {}", nextItem.getId());

                logger.debug("Next item - User Role : {}", nextItem.getUserRole());

                // landApp.setWorkflowTask(nextItem); //set to workflow state of approve
                landApp.setWorkflowItem(nextItem); //set to workflow state of approve

                setApprovalComment(landApp, comment, AppConstants.APPROVE, user);

                landApplicationDAO.updateLandApplication(landApp, user);

                //upload file
                if (landApplication.getDocumentList() != null) {
                    try {
                        logger.debug("Uploading files");
                        logger.debug("landApplication.getDocumentList size:{}", landApplication.getDocumentList().size());
                        documentManagementService.uploadfiles(user, landApplication.getDocumentList(), landApp.getId());
                    } catch (Exception e) {
                        logger.debug("Error :{}", e);
                    }
                }
            }
        }
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void approveSignDocApplication(LandApplication landApplication, String comment, User user) {
        //TODO : check permission
        logger.debug("\n\n\nApplication ID : {}", landApplication.getId());
        LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);

        if (landApp != null) {

            landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.SIGNED_ALIENATION_DOCUMENT_APPROVED,
                    landApp.getWorkflowItem().getId(), user));

            if (landApplication.getComment() != null) {
                landApp.setComment(landApplication.getComment());
            }
            setApprovalComment(landApp, comment, AppConstants.APPROVE, user);

            landApplicationDAO.updateLandApplication(landApp, user);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectSignDocApplication(LandApplication landApplication, String comment, User user) {
        //TODO : check permission
        logger.debug("\n\n\nApplication ID : {}", landApplication.getId());
        LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);

        if (landApp != null) {
            //  logger.debug("\n\n\nCurrent item - Action : {}", landApp.getWorkflowTask().getAction());

            // landApp.setStatus(LandApplication.State.FULLY_APPROVED);

            landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.SIGNED_PRINTED_ALIENATION_DOCUMENT,
                    landApp.getWorkflowItem().getId(), user));

            if (landApplication.getComment() != null) {
                landApp.setComment(landApplication.getComment());
            }
            setApprovalComment(landApp, comment, AppConstants.REJECTE, user);

            landApplicationDAO.updateLandApplication(landApp, user);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectLandApplication(long id, String comment, User user) {
        //TODO : check permission
        logger.debug("Reject Land Application :  {} ", user.getUsername());
        LandApplication landApp = getLandApplicationByIdUKey(id, user);
        //todo: handle error on reject state == null

        //int rejectItemId = landApp.getWorkflowItem().getNextItemId();

        WorkflowItem nextItem = workflowService.getNextWorkflowItem(WorkflowTask.REJECTED,
                landApp.getWorkflowItem().getId(), user);

        //WorkflowItem rejectItem = workflowService.getWorkflowItemById(rejectItemId);

        landApp.setWorkflowItem(nextItem);//set workflow state to reject
        setApprovalComment(landApp, comment, AppConstants.REJECTE, user);
        landApplicationDAO.updateLandApplication(landApp, user);
        smsSenderService.notifyBySms(user.getDsDivisions(), user, landApp.getRefNumber() + " Rejected");

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void rejectInitLandApplication(long applicationId, String comment, User user) {
        LandApplication landApplication = getLandApplicationByIdUKey(applicationId, user);
        //landApplicationDAO.updateLandApplication(landApplication, user);
        if (user.isAuthorized(Permission.APPROVE_REJECT_INITIAL_LAND_APPLICATION)) {
            landApplication.setInitialStatus(LandApplication.State.INITIAL_APPLICATION_REJECTED);

            //landApplication.setComment(comment);
            //set Approval Comment
            setApprovalComment(landApplication, comment, AppConstants.REJECTE, user);

            //set Initial RefNo
            //landApplication.setRefNumber("ILA/" + new Date().getYear() + "/" + landApplication.getId());
            landApplication.setRefNumber(AppConstants.INITIAL_APP_PRIFIX + "/" +
                    landApplication.getDsDivision().getEnDivisionName().substring(0, 4).toUpperCase() + "/" +
                    landApplication.getId());
            logger.debug("Initial RefNo : {}", landApplication.getRefNumber());

            landApplicationDAO.updateLandApplication(landApplication, user);
            // Notification of land alienation application rejection to all LOs

            String emailSubject = "Initial Land Application Rejection";
            String emailedMessage = "The initial land application of " + landApplication.getHolder().getName() + " which is referenced by number : " + landApplication.getRefNumber() + " has been rejected by ";
            Set<DSDivision> dsDivs = user.getDsDivisions();
            List<String> roles = new ArrayList<String>();
            roles.add("LO");
            mailSenderService.notifyToAll(dsDivs, roles, user, emailSubject, emailedMessage);
            smsSenderService.notifyBySms(dsDivs, user, landApplication.getRefNumber() + " Rejected");
        } else {
            handleELandRuntimeException(user.getUsername() +
                    "Doesn't have permission to reject initial land Application", ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    private void setApprovalComment(LandApplication existing, String approvalComment, String approveStr, User user) {
        if (approvalComment == null) {
            approvalComment = "";
        }

        if (existing.getComment() != null) {
            existing.setComment(existing.getComment() + "\n" + approvalComment + "\n" + approveStr + " by :" + user.getUsername() + ", Date : " + new Date() + "\n");
        } else {
            existing.setComment(approvalComment + "\n" + approveStr + " by :" + user.getUsername() + ", Date : " + new Date() + "\n");
        }

    }

    private void setObjections(LandApplication existing, String objection, User user) {
        if (objection != null && objection.length() > 0) {
            if (existing.getObjections() != null) {
                existing.setObjections(existing.getObjections() + "\n" + objection + "\n" + " by :" + user.getUsername() + ", Date : " + new Date() + "\n");
            } else {
                existing.setObjections(objection + "\n" + " by :" + user.getUsername() + ", Date : " + new Date() + "\n");
            }
        }
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApprovedApplicationList(User user) {
        return landApplicationDAO.getInitialApplicationsByState(user, LandApplication.State.INITIAL_APPLICATION_APPROVED);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationListByStateAndAM(User user, LandApplication.State state,
                                                                int alienationMethod) {
        return landApplicationDAO.getApplicationsByStateAndAM(user, state, alienationMethod);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getShortListedCandidates(EnumSet<WorkflowTask> stateSet, int alienationMethod) {
        return landApplicationDAO.getShortListedCandidates(stateSet, alienationMethod);
    }


    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsToBeCompleted(User user) {
        logger.debug("get Applications To Be Completed : ", user.getUsername());
        EnumSet<WorkflowTask> stateSet = EnumSet.of(WorkflowTask.INTERVIEW_COMPLETED,
                WorkflowTask.OBJECTION_HANDLING_APPROVED);
        return landApplicationDAO.getApplicationsByStates(user, stateSet);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByState(User user, WorkflowTask state) {
        logger.debug("get Applications by Sate : ", user.getUsername());
        return landApplicationDAO.getApplicationsByState(user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateAndDistrict(User user, WorkflowTask state, int districtId) {
        logger.debug("Get Applications by State and District : ", user.getUsername());
        return landApplicationDAO.getApplicationsByStateAndDistrict(user, state, districtId);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateAndDsId(WorkflowTask state, int dsDivisionId, User user) {
        logger.debug("Get Applications by State and DS Divisiaon ID : ", user.getUsername());
        return landApplicationDAO.getApplicationsByStateAndDsId(state, dsDivisionId, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationsByPersonName(String holderName, User user, WorkflowTask state) {
        logger.debug("Filter alienations by person name {} user {}", holderName, user);
        return landApplicationDAO.searchAlienationsByPersonName(holderName, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationsByNIC(String holderNIC, User user, WorkflowTask state) {
        logger.debug("Filter alienations by person NIC {} user {}", holderNIC, user);
        return landApplicationDAO.searchAlienationsByPersoNIC(holderNIC, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationByAlienationSerialNumber(long alienationSerialNumber, User user, WorkflowTask state) {
        logger.debug("Filter alienations by alienation serial number {} user {}", alienationSerialNumber, user);
        return landApplicationDAO.searchAlienationsByAlienationSerialNumber(alienationSerialNumber, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationByLandSerialNumber(long landSerialNumber, User user, WorkflowTask state) {
        logger.debug("Filter alienations by land serial number {} user {}", landSerialNumber, user);
        return landApplicationDAO.searchAlienationsByLnadSerialNumber(landSerialNumber, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationByAlienationReferenceNumber(String alienationNumber, User user, WorkflowTask state) {
        logger.debug("Filter alienations by alienation number {} user {}", alienationNumber, user);
        return landApplicationDAO.searchAlienationByAlienationReferenceNumber(alienationNumber, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAlienationByMethodId(int alienationMethodId, User user, WorkflowTask state) {
        logger.debug("Filter alienations by alienation method {} user {}", alienationMethodId, user);
        return landApplicationDAO.searchAlienationsByAlienationMethodId(alienationMethodId, user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchAllAlienationByMethodId(User user, WorkflowTask state) {
        logger.debug("Filter alienations by all alienation methods user {}", user);
        return landApplicationDAO.searchAllAlienationsByAlienationMethodId(user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByWorkFlowItemId(User user, int itemId) {
        logger.debug("get Applications by Workflow Id : ", user.getUsername());
        return landApplicationDAO.getApplicationsByWorkFlowItemId(user, itemId);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getInitialApplicationsByState(User user, LandApplication.State state) {
        logger.debug("get Applications by Sate : ", user.getUsername());
        return landApplicationDAO.getInitialApplicationsByState(user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateSet(User user, EnumSet<WorkflowTask> stateSet) {
        logger.debug("get Applications by Sate set : ", user.getUsername());
        return landApplicationDAO.getApplicationsByStates(user, stateSet);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateSetGn(User user, int gnId, EnumSet<WorkflowTask> stateSet) {
        logger.debug("get Applications by Sate set : ", user.getUsername());
        return landApplicationDAO.getApplicationsByStatesGn(user, gnId, stateSet);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByWorkflowState(User user, WorkflowTask workflowTask) {
        logger.debug("get Applications by Workflow Sate : ", user.getUsername());
        return landApplicationDAO.getApplicationsByWorkflowState(user, workflowTask);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getLandApplicationListByAlienationType(int alienationType, User user) {
        logger.debug("get Applications by alienation type  : {} ", alienationType);
        return landApplicationDAO.getLandApplicationListByAlienationType(alienationType, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getSelectedLandApplicationListByAlienationType(int alienationType, User user) {
        logger.debug("get Applications by alienation type  : {} ", alienationType);
        return landApplicationDAO.getSelectedLandApplicationListByAlienationType(alienationType, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationList(User user) {
        logger.debug("get Applications List   : {} ");
        return landApplicationDAO.getApplicationList(user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchApplicationsOfDSDivisionByPersonName(String personName, User user) {
        logger.debug("Filter application of DSDivision {} by person name {}", personName);
        return landApplicationDAO.searchApplicationsOfDSDivisionByPersonName(personName, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchApplicationsOfDSDivisionByNIC(String nic, User user) {
        logger.debug("Filter application of DSDivision  by NIC {}", nic);
        return landApplicationDAO.searchApplicationsOfDSDivisionByNIC(nic, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchApplicationsByDsId(int dsDivisionId, User user) {
        logger.debug("Filter application of DSDivision {} ", dsDivisionId);
        return landApplicationDAO.searchApplicationsByDsId(dsDivisionId, user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> searchApplicationsByDistrictId(int districtId, User user) {
        logger.debug("Filter application of DSDivision List By {} ", user.getUsername());
        return landApplicationDAO.searchApplicationsByDistrictId(districtId, user);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateDueDateLandApplication(LandApplication landApplication, User user) {

        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            landApplicationDAO.updateLandApplication(landApplication, user);
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to update land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveSetUpAction(LandApplication landApplication, User user) {

        logger.debug("saveSetUpAction Application ID : {}", landApplication.getId());


        if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
            LandApplication landApp = getLandApplicationByIdUKey(landApplication.getId(), user);

            if (landApp != null) {

                //landApp.setStatus(LandApplication.State.CONDITION_SATISFIED);

                landApp.setWorkflowItem(workflowService.getNextWorkflowItem(WorkflowTask.CONDITION_SATISFIED,
                        landApp.getWorkflowItem().getId(), user));

                landApplicationDAO.updateLandApplication(landApp, user);
            }
        } else {
            logger.debug("No permission");
            handleELandRuntimeException(user.getFullName() + " doesn't have permission to update land Application",
                    ErrorCodes.UNAUTHORIZED_ACCESS);
        }
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateSetAndUser(User user) {
        logger.debug("get Applications by Sate And User : {}", user.getUsername());
        return landApplicationDAO.getApplicationsByStateSetAndUser(user);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByUser(User user) {
        logger.debug("get Applications by  User : {}", user.getUsername());
        return landApplicationDAO.getApplicationsByUser(user);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveLeasePaymentDetail(LandApplication landApplication, User user) {
        //   if (user.isAuthorized(Permission.MANAGE_DETAIL_LAND_APPLICATION)) {
        logger.debug("save Lease Payment Detail land application id : {}", landApplication.getId());


        LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

        //set Lease Payment Detail
        LeaseDetail leaseDetail;
        if (existingApplication.getAlienationDetails().getLeaseDetail() != null) {
            leaseDetail = existingApplication.getAlienationDetails().getLeaseDetail();
        } else {
            leaseDetail = new LeaseDetail();
        }
        LeaseDetail newLeaseDetail = landApplication.getAlienationDetails().getLeaseDetail();
  /*      leaseDetail.setLeaseStartDate(newLeaseDetail.getLeaseStartDate());
        leaseDetail.setLeasePeriod(newLeaseDetail.getLeasePeriod());
        leaseDetail.setLeasePeriodInWord(newLeaseDetail.getLeasePeriodInWord());
        leaseDetail.setPremium(newLeaseDetail.getPremium());
        leaseDetail.setPremiumInWord(newLeaseDetail.getPremiumInWord());
        leaseDetail.setAnnualLeaseAmount(newLeaseDetail.getAnnualLeaseAmount());
        leaseDetail.setAnnualLeaseAmountInWord(newLeaseDetail.getAnnualLeaseAmountInWord());
        leaseDetail.setLeaseDiagramNo(newLeaseDetail.getLeaseDiagramNo());
        leaseDetail.setFieldSheetNo(newLeaseDetail.getFieldSheetNo());*/

        existingApplication.getAlienationDetails().setLeaseDetail(leaseDetail);

        landApplicationDAO.updateLandApplication(existingApplication, user);
    }

    //Create SLC User
    private Map<String, String> createSLCUser(LandApplication landApplication, User user) {
        logger.debug("Attempt  to create SLC user :{}", user.getUsername());

        Map<String, String> messages = new TreeMap<String, String>();

        try {

            User slcUser = new User();

            String password = getRandomPassword();
            messages.put("slcPassword", password);
            //password = "password";
            //String password = getRandomPassword(getRandomInteger());

            //todo set random password
            //slcUser.setPasswordHash(password);
            slcUser.setPasswordHash(password);
            slcUser.setRole(roleDAO.getRole(AppConstants.SLC_USER_ROLE));
            slcUser.setUsername(landApplication.getRefNumber());
            //slcUser.setUsername("slc");
            slcUser.setFullName(landApplication.getHolder().getName());
            String eMail = landApplication.getHolder().getContacts().getEmail();
            String mobile = landApplication.getHolder().getContacts().getMobile();
            messages.put("slcEmail", eMail);
            messages.put("slcMobile", mobile);
            slcUser.setEmail(eMail);
            slcUser.setMobile(mobile);
            userManager.createUser(slcUser, user);

            //set SLC to Application
            landApplication.getHolder().setSlcUser(slcUser);
            landApplicationDAO.updateLandApplication(landApplication, user);

            if (eMail != null && eMail.length() > 0) {
                sendMassageMail(slcUser, password);
            }
            if (mobile != null || mobile.length() > 0) {
                boolean smsSuccess = sendSMS(slcUser, password);
                messages.put("smsSuccess", String.valueOf(smsSuccess));
            }

        } catch (Exception e) {
            logger.debug("Exception in create SLC user :{}", e);
            e.printStackTrace();

        }

        return messages;
    }

    private boolean sendMassageMail(User registerUser, String password) {
        String msg = "A user account has been created with the following Username and Password." +
                "\nUser Name : " + registerUser.getUsername() +
                "\nPassword : " + password +
                "\n\nPlease login to the system through the following link and change your password." +
                "\n" + AppConstants.APPLICATION_URL;

        String mail = registerUser.getEmail();
        boolean mailSent = mailSenderService.sendMail("from@no-spam.com", mail, "SLIMS : User Creation", msg);

        return mailSent;
    }

    private boolean sendSMS(User registerUser, String password) {
        String msg = "Your (" + registerUser.getFullName() + ") user account has been created " +
                "\nUser Name : " + registerUser.getUsername() +
                "\nPassword : " + password +
                "\n\nPlease login to the system through the following link and change your password." +
                "\n" + AppConstants.APPLICATION_URL;

        return smsSenderService.sendSmsToSlcUser(registerUser, msg);
    }


    private String getRandomPassword() {
        StringBuffer buffer = new StringBuffer();
        Random random = new Random();
        int length = random.nextInt(6) + 8;
        char[] charArray = new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
                'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
                '8', '9'};
        for (int i = 0; i < length; i++) {
            buffer.append(charArray[random.nextInt(charArray.length)]);
        }
        return buffer.toString();
    }


    private void handleELandRuntimeException(String message, int code) {
        logger.error(message);
        throw new ELandRuntimeException(message, code);
    }

    private int getMarks(LandApplication application) {
        int marks = 0;
        BigDecimal annualIncome = application.getAnnualIncome();

        logger.debug("Paased Annual Income  : {} ", annualIncome);

        /*marks for annual income*/
        if (annualIncome.compareTo(new BigDecimal(ShortlistConstants.ANNUAL_INCOME_LEVEL_1)) == -1) {
            marks += ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_1;
            logger.debug("Marks Income Level 1  : {} ", ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_1);
            logger.debug("Aggregated Marks Income Level 1  : {} ", marks);

        } else if (annualIncome.compareTo(new BigDecimal(ShortlistConstants.ANNUAL_INCOME_LEVEL_2)) == -1) {
            marks += ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_2;
            logger.debug("Marks Income Level 2  : {} ", ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_2);
            logger.debug("Aggregated Marks Income Level 2  : {} ", marks);

        } else if (annualIncome.compareTo(new BigDecimal(ShortlistConstants.ANNUAL_INCOME_LEVEL_3)) == -1) {
            marks += ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_3;
            logger.debug("Marks Income Level 3  : {} ", ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_3);
            logger.debug("Aggregated Marks Income Level 3  : {} ", marks);

        } else if (annualIncome.compareTo(new BigDecimal(ShortlistConstants.ANNUAL_INCOME_LEVEL_4)) == -1) {
            marks += ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_4;
            logger.debug("Marks Income Level 4  : {} ", ShortlistConstants.ANNUAL_INCOME_MARKS_LEVEL_4);
            logger.debug("Aggregated Marks Income Level 4  : {} ", marks);
        }

        /*marks for Age*/
        if (application.getHolder() != null) {
            if (application.getHolder().getDateOfBirth() != null) {
                long ageInMillis = new Date().getTime() - application.getHolder().getDateOfBirth().getTime();
                Date ageDay = new Date(ageInMillis);
                int age = ageDay.getYear();
                if (ShortlistConstants.AGE_LEVEL_18 < age && age < ShortlistConstants.AGE_LEVEL_25) {
                    marks += ShortlistConstants.AGE_MARKS_LEVEL_3;
                    logger.debug("Marks Age Level 3  : {} ", ShortlistConstants.AGE_MARKS_LEVEL_3);
                    logger.debug("Aggregated Marks Age Level 3  : {} ", marks);
                } else if (age < ShortlistConstants.AGE_LEVEL_35) {
                    marks += ShortlistConstants.AGE_MARKS_LEVEL_1;
                    logger.debug("Marks Age Level 1  : {} ", ShortlistConstants.AGE_MARKS_LEVEL_1);
                    logger.debug("Aggregated Marks Age Level 1  : {} ", marks);
                } else if (age < ShortlistConstants.AGE_LEVEL_45) {
                    marks += ShortlistConstants.AGE_MARKS_LEVEL_2;
                    logger.debug("Marks Age Level 2  : {} ", ShortlistConstants.AGE_MARKS_LEVEL_2);
                    logger.debug("Aggregated Marks Age Level 2  : {} ", marks);
                } else if (age > ShortlistConstants.AGE_LEVEL_45) {
                    marks += ShortlistConstants.AGE_MARKS_LEVEL_4;
                    logger.debug("Marks Age Level 4  : {} ", ShortlistConstants.AGE_MARKS_LEVEL_4);
                    logger.debug("Aggregated Marks Age Level 4  : {} ", marks);
                }
            }
        }

        int durationOfResidency = application.getDurationOfResidency();
        if (durationOfResidency < ShortlistConstants.DURATION_OF_RESIDENCY_LEVEL_5Y) {
            marks += ShortlistConstants.DURATION_OF_RESIDENCY_MARKS_LEVEL_5;
        } else if (durationOfResidency < ShortlistConstants.DURATION_OF_RESIDENCY_LEVEL_15Y) {
            marks += ShortlistConstants.DURATION_OF_RESIDENCY_MARKS_LEVEL_4;
        } else if (durationOfResidency < ShortlistConstants.DURATION_OF_RESIDENCY_LEVEL_20Y) {
            marks += ShortlistConstants.DURATION_OF_RESIDENCY_MARKS_LEVEL_3;
        } else {
            marks += ShortlistConstants.DURATION_OF_RESIDENCY_MARKS_LEVEL_1;
        }
        int residencialType = application.getResidencialType();
        switch (residencialType) {
            case 0:
                marks += ShortlistConstants.RESIDENCIAL_TYPE_MARKS_LEVEL_4;
                break;
            case 1:
                marks += ShortlistConstants.RESIDENCIAL_TYPE_MARKS_LEVEL_5;
                break;
            case 2:
                marks += ShortlistConstants.RESIDENCIAL_TYPE_MARKS_LEVEL_3;
                break;
            case 3:
                marks += ShortlistConstants.RESIDENCIAL_TYPE_MARKS_LEVEL_2;
                break;
            case 4:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_1;
                break;
        }
        if (application.isHeritageOrLegallyDeservedLand()) {
            marks = ShortlistConstants.LEGALLY_DESERVED_PROPERTY_MARKS_LEVEL_1;
        }
        int abilityToDevelopTheLand = application.getAbilityToDevelopTheLand();
        switch (abilityToDevelopTheLand) {
            case 0:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_5;
                break;
            case 1:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_4;
                break;
            case 2:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_3;
                break;
            case 3:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_2;
                break;
            case 4:
                marks += ShortlistConstants.ABILITY_TO_DEVELOP_THE_LAND_MARKS_LEVEL_1;
                break;
        }
        int socialActivities = application.getSocialActivities();
        switch (socialActivities) {
            case 0:
                marks += ShortlistConstants.SOCIAL_ACTIVITIES_MARKS_LEVEL_5;
                break;
            case 1:
                marks += ShortlistConstants.SOCIAL_ACTIVITIES_MARKS_LEVEL_4;
                break;
            case 2:
                marks += ShortlistConstants.SOCIAL_ACTIVITIES_MARKS_LEVEL_3;
                break;
            case 3:
                marks += ShortlistConstants.SOCIAL_ACTIVITIES_MARKS_LEVEL_2;
                break;
            case 4:
                marks += ShortlistConstants.SOCIAL_ACTIVITIES_MARKS_LEVEL_1;
                break;
        }
        List<Child> childrenList = application.getHolder().getChildren();
        int marksForChild = 0;
        if (childrenList != null && childrenList.size() > 0) {
            for (Child child : childrenList) {
                if (child.getDateOfBirth() != null) {
                    long ageInMillis = new Date().getTime() - child.getDateOfBirth().getTime();
                    Date ageDay = new Date(ageInMillis);
                    int age = ageDay.getYear();
                    if (ShortlistConstants.CHILD_AGE_LEVEL_10Y > age) {
                        marksForChild += ShortlistConstants.CHILD_AGE_MARKS_LEVEL_LEVEL_1;
                    } else {
                        marksForChild += ShortlistConstants.CHILD_AGE_MARKS_LEVEL_LEVEL_2;
                    }
                    if (child.isDisable()) {
                        marksForChild += ShortlistConstants.CHILD_AGE_MARKS_LEVEL_LEVEL_3;
                    }
                }
            }
        }
        if (marksForChild >= ShortlistConstants.CHILD_AGE_MARKS_LEVEL_LEVEL_MAX) {
            marks += ShortlistConstants.CHILD_AGE_MARKS_LEVEL_LEVEL_MAX;
        } else {
            marks += marksForChild;
        }

        logger.debug("Final Marks : {} ", marks);
        return marks;
    }

    private void setCommonFields(LandApplication landApplication, WorkflowTask workflowTask, User user) {

        LandApplication existingApplication = getLandApplicationByIdUKey(landApplication.getId(), user);

        landApplication.setWorkflowItem(workflowService.getNextWorkflowItem(workflowTask,
                landApplication.getWorkflowItem().getId(), user));

        landApplication.setDsDivision(existingApplication.getDsDivision());
        landApplication.setInitApplicationId(existingApplication.getInitApplicationId());

        //add slcUser
        landApplication.getHolder().setSlcUser(existingApplication.getHolder().getSlcUser());
        landApplication.setRefNumber(existingApplication.getRefNumber());

        landApplication.setDueDate(existingApplication.getDueDate());
        landApplication.setLetterCount(existingApplication.getLetterCount());

        landApplication.getLifeCycleInfo().setCreatedTimeStamp(existingApplication.getLifeCycleInfo().getCreatedTimeStamp());
        landApplication.getLifeCycleInfo().setCreatedUser(existingApplication.getLifeCycleInfo().getCreatedUser());

        landApplication.setAlienationDetails(existingApplication.getAlienationDetails());
    }

    private void setMarksForLandApplications(LandApplication landApplication) {
        boolean foundLandPermit = false;
        for (AlienationMethod aMethod : landApplication.getAlienationMethods()) {
            if (AppConstants.LAND_PERMIT == aMethod.getId()) {
                foundLandPermit = true;
            }
        }
        if (foundLandPermit) {
            landApplication.setMarks(getMarks(landApplication));
        }
    }

    public boolean isObjectionsEnabled(LandApplication landApplication) {
        long dayDiff = (new Date().getTime() - landApplication.getLifeCycleInfo().getCreatedTimeStamp().getTime()) / (24 * 60 * 60 * 1000);
        logger.debug("Day Diff : {} from {}", dayDiff, landApplication.getLifeCycleInfo().getCreatedTimeStamp().toString());
        return (dayDiff < AppConstants.OBJECTION_EXP_DAYS) ? true : false;
    }

    @Override
    public List<Object[]> getLandApplicationStats(int id, String searchBy, int initAppState, int wftState, Date fromDate, Date toDate, String language) {
        return landApplicationDAO.getLandApplicationStatistics(id, searchBy, initAppState, wftState, fromDate, toDate, language);
    }
}
